/*
 *  Copyright 2012 yura.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */

package org.opu.pc.ui.client;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.opu.pc.services.beans.AbstractBean;
import org.opu.pc.ui.client.actions.AbstractAction;
import org.opu.pc.ui.client.actions.Exit;
import org.opu.pc.ui.client.actions.SerialAction;
import org.opu.pc.ui.client.widgets.TableRender;
import org.opu.pc.ui.util.ConfigPath;
import org.opu.pc.ui.util.FileIO;
import org.opu.pc.ui.util.JProperties;
import org.opu.pc.ui.util.Logger;
import org.opu.pc.ui.util.ResourceHandle;

/**
 *
 * @author yura
 */
public class MainViewImpl extends JFrame implements MainView {

	private static final long serialVersionUID = 5460926714646978788L;
	
	public static final String LOCATION = "location";
    public static final String MAXIMIZE = "maximize";
    public static final String SIZE = "size";
    public static final String LAF = "laf";

    /** Properties map with all properties of window. */
    private JProperties configs = new JProperties();

    private List<PropertyChangeListener> changeListeners =
            new ArrayList<PropertyChangeListener>();

    private Logger logger = Logger.create(this.getClass());
    private List<AbstractBean> model = new ArrayList<AbstractBean>();
    private SerialAction lastAction = null;
    private MainMenuBar menuBar = new MainMenuBar(this);
    private MainToolBar toolBar = new MainToolBar();
    private BeanView beanView;
    private Map<Class<?>, TableRender<?>> renders;

    public MainViewImpl(BeanView beanView, List<TableRender<?>> renders) {
    	super(ResourceHandle.getApplicationTitle());
        this.beanView = beanView;
        getContentPane().add(new JScrollPane(beanView.asComponent()));
        setIconImage(ResourceHandle.getWindowImage());
        
        this.renders = new HashMap<Class<?>, TableRender<?>>();
        for (TableRender<?> tableRender : renders) {
			this.renders.put(tableRender.getRenderingClass(), tableRender);
		}
        
        try {
            FileIO.load(ConfigPath.getInstance().getFrameProp(), configs);
            setLocation(configs.getPoint(LOCATION));
            setSize(configs.getDimension(SIZE));
        } catch (IOException ex) {
            // It's normal
            logger.warning("It's normal if you run application at first time");
            logger.warning(ex);
            setSize(640, 480);
            setLocationRelativeTo(null);
        }
        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        
        this.beanView.addListSelectionListener(new ListSelectionListener() {
			
			@Override
			public void valueChanged(ListSelectionEvent e) {
				propertyChange(SELECTED_BEANS, null, getSelectedBeans());
			}
		});
    }

    @Override
    public void addChangeListener(PropertyChangeListener changeListener) {
        changeListeners.add(changeListener);
    }

    @Override
    public void fireState() {
        propertyChange(CONTENT_TYPE, null, null);
        propertyChange(LAST_ACTION_CHANGE, null, lastAction);
		propertyChange(SELECTED_BEANS, null, getSelectedBeans());
    }

    private void propertyChange(String name, Object oldValue, Object newValue){
        for (PropertyChangeListener changeListener : changeListeners) {
            changeListener.propertyChange(new PropertyChangeEvent(this, name,
                    oldValue, newValue));
        }
    }

    @Override
    public JFrame asFrame() {
        return this;
    }

    @Override
    public JDialog getDialog() {
        return new JDialog(this, getTitle(), true);
    }

    @Override
    public void update() {
        if (lastAction != null){
            lastAction.runAgaion();
        }
    }

    @Override
    public void initActions(Collection<? extends AbstractAction> actions) {
        Map<String, AbstractAction> map = new HashMap<String, AbstractAction>();
        for (AbstractAction action : actions) {
            map.put(action.getName(), action);
        }

        final Exit exit = (Exit) map.get(Exit.MNAME);

        exit.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                File file = ConfigPath.getInstance().getFrameProp();

                configs.setPoint(LOCATION, asFrame().getLocation());
                configs.setDimension(SIZE, asFrame().getSize());
                configs.setBoolean(MAXIMIZE, asFrame().isMaximumSizeSet());

                try {
                    FileIO.store(file, configs, "window");
                } catch (IOException ex) {
                    logger.error("When store properties:");
                    logger.error(ex);
                }
            }
        });

        addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                exit.action(null);
            }
        });

        menuBar.initMenuBar(map);
        toolBar.initComponent(map);

        setJMenuBar(menuBar);
        getContentPane().add(toolBar, BorderLayout.NORTH);
    }

    @Override
    public void setContent(Collection<? extends AbstractBean> beans, 
    		Class<?> beansClass) {
        model.clear();
        model.addAll(beans);
        propertyChange(CONTENT_TYPE, null, beansClass);
        renders.get(beansClass).rendView(model, beanView);
    }

    @Override
    public List<? extends AbstractBean> getSelectedBeans() {
        int[] indexes = beanView.getSelectedIndexes();
        if (indexes == null || indexes.length < 1){
            return null;
        }

        List<AbstractBean> selection = new ArrayList<AbstractBean>();
        for (int i : indexes) {
            selection.add(model.get(i));
        }

        return selection;
    }

    @Override
    public void strartAction(AbstractAction action) {
        // TODO: show indicator
        if (action instanceof SerialAction){
            SerialAction old = lastAction;
            propertyChange(LAST_ACTION_CHANGE, old, lastAction = (SerialAction) action);
        }
    }

    @Override
    public void stopAction(AbstractAction action) {
        // TODO: hide indicator
    }

    @Override
    public void cancelCurrentAction() {
        AbstractAction.stopCurrentAction();
    }

}
